import org.molamil.acto.core.Logger;
import org.molamil.acto.pages.AbstractMovieContext;
import org.molamil.acto.pages.MovieContext;
import org.molamil.acto.pages.PageContext;
import org.molamil.acto.pages.factory.AbstractPagesFactory;
import org.molamil.acto.pages.factory.DependsError;
import org.molamil.acto.pages.factory.DependsNotFoundError;
import org.molamil.acto.pages.factory.PageNotFoundError;
import org.molamil.acto.pages.factory.ParentError;
import org.molamil.commons.StringUtil;

/**
 * XXX: Document.
 * 
 * @author Jorge Hernandez
 */
class org.molamil.acto.pages.factory.PagesFactoryFinisher {
	
	
	// Constants
	
	public static var ERROR_DEPENDS_SELF:String = "ERROR: A movie can not depend on itself (\"{movie}\").";
	public static var ERROR_DEPENDS_DUPLICATE:String = "ERROR: Duplicate depends (\"{movie}\").";
	public static var ERROR_DEPENDS_NOT_FOUND:String = "ERROR: A depended movie could not be found (\"{movie}\").";
	public static var ERROR_PARENT_NOT_FOUND:String = "ERROR: A parent page could not be found (\"{movie}\").";
	
	
	// Properties
	
	private static var log:Logger = Logger.getLogger("PagesFactoryFinisher");
	
	
	// Functions
	
	public static function run(factory:AbstractPagesFactory):Void {
		log.debug("run()");
		runPages(factory);
		runMovies(factory);
	}
	
	public static function runPages(factory:AbstractPagesFactory):Void {
		
		var a:Array = factory.getPages();
		
		log.debug("runPages(), length = " + a.length);
		
		runDepends(factory, a);
		runParent(factory, a);		runAlias(factory, a);
		
	}
	
	public static function runMovies(factory:AbstractPagesFactory):Void {
		
		var a:Array = factory.getMovies();
		
		log.debug("runMovies(), length = " + a.length);
		
		runDepends(factory, a);
		
	}
	
	private static function runDepends(factory:AbstractPagesFactory, a:Array):Void {
		for (var i:Number = 0; i < a.length; i++) {
			var context:AbstractMovieContext = a[i];
			if (context.depends != null) {
				var dependsHistory:Array = new Array();
				for (var j:Number = 0; j < context.depends.length; j++) {
					var name:String = context.depends[j];
					for (var k:Number = 0; k < dependsHistory.length; k++) {
						if (dependsHistory[k] == name) {
							var msg:String = StringUtil.replace(ERROR_DEPENDS_DUPLICATE, "{movie}", name);
							throw new DependsError(msg);
						}
					}
					dependsHistory.push(name);
					var movie:MovieContext = factory.getMovie(name);
					if (movie == null) {
						var msg:String = StringUtil.replace(ERROR_DEPENDS_NOT_FOUND, "{movie}", name);
						throw new DependsNotFoundError(msg);	
					}
					if (name == context.name) {
						var msg:String = StringUtil.replace(ERROR_DEPENDS_SELF, "{movie}", name);
						throw new DependsError(msg);	
					}
				}
			}
		}
	}
	
	private static function runParent(factory:AbstractPagesFactory, a:Array):Void {
		//TODO: Check parent self.
		for (var i:Number = 0; i < a.length; i++) {
			var context:PageContext = a[i];
			if (context.parentName != null) {
				var parent:PageContext = factory.getPage(context.parentName); 
				if (parent == null) {
					var msg:String = StringUtil.replace(ERROR_PARENT_NOT_FOUND, "{movie}", context.parentName);
					throw new ParentError(msg);	
				}
				context.parent = parent;
				parent.children.push(context);
				context.level = getPageLevel(factory, context.name);
			}
		}
	}
	
	private static function runAlias(factory:AbstractPagesFactory, a:Array):Void {
		//TODO: Implement.
	}
	
	private static function getPageLevel(factory:AbstractPagesFactory, name:String):Number {
		var level:Number = 0;
		var page:PageContext = factory.getPage(name);
		if (page == null)
			throw new PageNotFoundError(); 
		if (page.parentName != null)
			level = getPageLevel(factory, page.parentName) + 1;
		return level;
	}
	
	
}